package com.example.demo3;
import org.elasticsearch.action.index.IndexResponse;
import com.google.gson.Gson;
import org.elasticsearch.client.Client;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class IfanrReviewCrawler {
    private static int refresh = 100; //预定按下”加载更多 ”按钮翻页次数
    private static boolean isinsert = true;
    //设为 true 表示数据直接存入 Elasticsearch , 设为 false 表示仅测试不入库
    private static WebDriver driver, innerDriver;
    private static WebDriverWait wait;
    private static int reviewCycler = 3;
    private static int reviewNum = 1;
    private static WebElement btnRefresh;
    private static String url;
    private static String title;
    private static String editorName;
    private static String content;
    private static String publishTime;
    private static String shares;
    private static String likes;
    private static String comments;
    private static ESClient esClient = new ESClient();
    private static Client client = esClient.getClient();
    private static Actions actions;

    public static void main(String[] args) {
	//初始化谷歌 Chrome 浏览器远程驱动
        try {
            ChromeOptions options = new ChromeOptions();
            options.setCapability("acceptInsecureCerts", true);
            WebDriver driver = new ChromeDriver(options);
            driver = new RemoteWebDriver(new URL("http://localhost:9515"),options);
        } catch (MalformedURLException e) {
            System.out.println("列表页面浏览器远程驱动创建失败,详细信息：" + e.
                    getMessage());
        }
	//访问产品评测页面
        driver.get("http://www.ifanr.com/category/review");
	//等待评测信息加载 ,完成的标志是检测 到前四 行评测标题出现,下拉刷新可以直接追加三行 ,之后全部以按钮形式刷新,

        Wait4Emerging("//div[@class='o-wrapper o-matrix o-matrix--large']/div[4]");
	//首先获取前四行评测,判断当前行包含评测的数量
        GetReviewBlock(4);
	//下拉刷新
                ((JavascriptExecutor) driver).executeScript("window.scrollTo(O,document.body.scrollHeight )");
	//等待接下来三行评测加载 ,完成的标志是第 7 行评测出现
        Wait4Emerging("//div[@class='o-wrapper o-matrix o-matrix--large']/div [7]");
	//获取接下来的三行产品评测的相关信息 ,方式同上
        GetReviewBlock(3);
	//按下 ”加 载更多 ”按钮继续刷新和获取产品评测
        for (int i = 0 ;i<refresh; i++){
            btnRefresh = driver.findElement(By.xpath("//button[@class='c-load-more_button js-load-more']"));
            btnRefresh.click();
            Wait4Emerging (
            "//div[@class='o-wrapper o-matrix o-matrix--large']/div [ " + (reviewNum + 2) + "]" );
            GetReviewBlock(3);
        }
    }

    // 成员1
    public static void Wait4Emerging(String strXpath) {
   while (true) {
            try {
                wait = new WebDriverWait(driver, Duration.ofSeconds(10));
                wait.until(ExpectedConditions.presenceOfElementLocated(By.
                        xpath(strXpath)));
                if (driver.findElement(By.xpath(strXpath)) != null)
                    break;
            } catch (NoSuchElementException nsee) {
                System.out.println("检测的信息、未找到 , 继续等待 。");
            } catch (TimeoutException te) {
                System.out.println("检 测 过程超出 10 秒预定 时间, 继续等待。");
            }
        }

    }

    // 成员2
    public static void GetReviewBlock(int rows) {
         for (int i = 0; i < rows ;i++){
      //当且仅当第一个评测 的 class 属性为 o -matrix row unit o - matrix_row unit-- 2 xl 时,该行有三个评测 ；
      //全为 o -matrix row un i t 时 ,该行有四个评测
                reviewCycler = driver.findElement(By.xpath(" //div[@class ='o-wrapper o-matrix o-matrix--large']/div[" + reviewNum + "]/div [1]")).getAttribute (" class ") . equals (" o-matrix_row_unit ") ? 4 :3;
        for (int j = 1; j <= reviewCycler; j++) {
            url =" http://www.ifanr.com/ " +
            driver.findElement(By.xpath ( "//div[@class = 'o-wrapper o-matrix o-matrix--large']/div [ " +
                    reviewNum+ "]/div["+j+ "]/div")).getAttribute("data-post-id");
            GetReviewDetail(url);
        }
          //一行产品评测信息采集结束后 ,切换到下一行
        reviewNum++;
    }

    }

    // 成员3
    public static void GetReviewDetail(String productLink) {
        try {
            ChromeOptions options = new ChromeOptions();
            options.setCapability("acceptInsecureCerts", true);
            WebDriver driver = new ChromeDriver(options);
            innerDriver = new RemoteWebDriver(new URL("http://localhost:9515 "),options);
        } catch (MalformedURLException e) {
            System.out.println("详 情页面 浏览 器远程驱 动创 建失败 , 详细信息 ："+ e.getMessage());
        }
        innerDriver.get(productLink);
      //获取页面元素 ,不 同的 页面有两种排版 ,调用 GetElement 方法进行判别
                title = GetElement("//h1[@class ='c-single-normal_title']", "// h1[@class = 'c-article-header_title']");


        editorName = GetElement("//p[@class='c-card-author_name' ] ", " //span[@class = 'o-article-header_author_name c-article-header_author_name']");
        content = GetElement("// article[@class = 'o-single-content__body__content c-article-content s-single-article js-article']","//article[@class ='c-article-content__body s-single-article js-article']") ;
        publishTime = innerDriver.findElement(By.xpath("// span [@class='c-article-header-meta_time']")) .getText ();
      //有些当年发布的评测,年份会被省略 ,此处补回年份信息
        if (!(publishTime.startsWith("20 "))) publishTime = GetYear() + publishTime;
        shares = innerDriver.findElement(By.xpath("//b[@class = ' j s - share -counter '] ")).getText();
        if (shares.equals("-")) shares ="o";
        likes = GetElement("//button[@class='c-article-sns__info c-card-meta__info c-card-meta__info--like js-article-like-count'] "," //span[@ class='c-article-sns__info c-card-meta__info c-card-meta__info--like js-article-like-count']");
        if (likes.equals("-")) likes =" 0";
        comments = GetElement("// button[@class ='c-article-sns__info c-card-meta__info c-card-meta__info--comments js-article-comment-count js-goto-comments'] ","// span[@class ='c-article-sns__info c-card-meta__info c-card-meta__info--comments js-article-comment-count js-goto-comments ']" );
        if (comments.equals("-")) comments ="0 ";
        System.out.println(url + "\n " + title + "\n " + editorName + " \n " + content.
                substring(0, 100) + " \n " + publishTime + "\n " + shares + " \n " + likes + " \n " +
                comments + " \n\n ");
      //将采集到的信息存入 Elasticsearch
        if (isinsert) {
            Map<String, Object> map = new HashMap<>();
            map.put("url ", url);
            map.put("title ", title);
            map.put("editorName ", editorName);
            map.put("content", content);
            map.put ("publishTime ",publishTime);
            map.put("shares ", shares);
            map.put(" likes ", likes);
            map.put("comments ", comments);
            String s = new Gson().toJson(map);
            IndexResponse response = client.prepareIndex ("ifanr ", " review").
            setSource(s).get();
        }
        //按下组合键 Alt+F4 来关闭 当 前窗口
        actions = new Actions (innerDriver);
        actions.keyDown(Keys.ALT).sendKeys(Keys.F4).keyUp(Keys.ALT).perform();
        innerDriver.close();
        innerDriver.quit();
    }

    }

    // 成员4
    public static String GetElement(String xpath1, String xpath2) {
         String element;
        try {
            element = innerDriver.findElement(By.xpath(xpath1)).getText();
        } catch (NoSuchElementException nsee) {
            element = innerDriver.findElement(By.xpath(xpath2)).getText();
        }
        return element;
    }

    }

    public static String GetYear() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        Date date = new Date();
        return sdf.format(date) + "-";
    }
}